为什么对象被new 以后在执行dup操作?

为什么对象被new 以后在执行dup操作?
今天有个朋友问我,为什么一个new一个对象的指令在new后面紧跟的是dup操作?他说搜了可能找到的
搜索引擎都找不到答案,包括翻了<<深入JAVA虚拟机指令>>这本书也没有任何说明.

我们先来看看为dup指令的作用,dup指令可以复制栈顶的一个字再压入栈,也就是把栈顶的内容做个备份.
大家知道,JAVA/CLR是完全基于栈的实现,任何操作都是入栈出栈,没有任何寄存器,所以如果要对某一操作
数做两次连续操作,那就要复制两次栈顶操作数,比如:
int x;
int y = x = 2;
当常数2被压入栈顶后,它要连续两次store到变量x和y,所以这里编译后肯定有一个dup操作:

 bipush  20
 dup
 istore_1
 istore_2
如果不做dup操作,那么istore_1将20存到内存中的x后,再istore_2要么没有操作数,要么是一个其它的操作数.
当然这在编译时对连续操作已经做dup操作了,所以不会真的出现这个情况.
那么new 指令后,为什么一定要dup操作呢?
因为java代码的new操作编译为虚拟机指令后,虚拟机指令new在堆上分配了内存并在栈顶压入了指向这段内存的
地址供任何下面的操作来调用,但是在这个操作数被程序员能访问的操作之前,虚拟机自己肯定要调用对象的
<init>方法,也就是如果程序员做一个 Type a = new Type();其实要连续两次对栈顶的操作数进行操作.其中一
次是虚拟机内部自动调用的,这种情况是99%以上存在的,而java 编译器是一种聪明的编译器,所以只要有new操作
就优化为将对象的地址操作数DUP,第一次调用invokespecial <init>时会弹出一个,下面一个留给对该对象访问
的操作,即使你的代码是:new Type();没有任何引用.有些虚拟机也会先dup(不同版本编译结果不同),然后<init>时弹出

一个操作数,后面会立即pop掉被复制的那个操作数.这样的做目的是为了编译优化.

有人说那可以直接从栈顶先store到内存中,需要操作的时候再load到栈顶啊,注意再没有<init>操作这前对象对于

程序员是不可见的,否则就会访问到残废的对象,所以只能是先<init>然后才能store到内存中.这两步操作的操作数必须都直接是原来已经存在栈中的,所以只能是dup.

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
### 回答1: 执行指令`ARRAY DW 100 DUP(?)`会在内存中分配100个字(16位)的空间,并且每个字节被初始化为问号'?'。寄存器本身不会发生任何变化,但是在程序执行,可以使用寄存器来访问这个数组中的元素。 例如,可以使用基址寄存器(如BX或BP)来存储数组的起始地址,然后使用偏移量来访问数组中的特定元素。例如,要访问数组的第一个元素,可以将偏移量设置为0,然后使用指令`MOV AX, [BX+0]`将该元素加载到AX寄存器中。 因此,执行指令`ARRAY DW 100 DUP(?)`不会直接影响寄存器的值,但是它会在内存中分配空间,从而允许程序使用寄存器来访问数组中的元素。 ### 回答2: 当执行指令ARRAY DW 100 DUP(?)后,会产生一个数组或一个数据类型为WORD的字节数组。这个数组的起始地址将存储在某个寄存器中。 具体来说,汇编器会为数组分配一块连续的内存空间,其大小为WORD(一个字)乘以100(数组的长度)。然后,汇编器会将该内存空间的起始地址存储在一个寄存器中。 寄存器的选择取决于所使用的汇编指令系统和编程语言。 例如,在8086汇编语言中,可能会将数组的起始地址存储在DS(数据段寄存器)中。 此外,也可以使用其他寄存器,如BX(基址寄存器)或SI(源变址寄存器),根据编程需要来决定。 总而言之,执行指令ARRAY DW 100 DUP(?)后,寄存器中的值将变为数组(或者字节数组)的起始地址。这样,我们就可以使用寄存器来定位和访问数组中的各个元素。 ### 回答3: 执行指令"ARRAY DW 100 DUP(?)"后,会在内存中分配一个数组,该数组名为ARRAY,数组中的元素为WORD类型,数组的长度为100个元素。每个元素的初始值为问号"?"。 执行这条指令后,寄存器不会发生任何变化。寄存器用于保存CPU执行指令过程中的临数据和地址等信息,而这条指令只是将内存中的一块连续区域分配给数组,并没有直接与寄存器相关的操作。 此,如果要在程序中访问或修改数组中的元素,需要使用基地址和偏移地址的方式进行操作,即使用数组名ARRAY加上偏移量的方法来定位到数组中的元素。通过将基地址和偏移地址加载到寄存器中,可以方便地进行数组元素的读取和写入操作。 例如,可以使用MOV指令将数组基地址加载到某个寄存器中,然后通过偏移地址来访问特定的数组元素,如MOV AX, OFFSET ARRAY,然后可以使用MOV指令将元素的值加载到另一个寄存器中,如MOV BX, [AX+2]。这样寄存器中存储了要访问的数组元素的值,可以进行进一步的操作。 总而言之,执行指令"ARRAY DW 100 DUP(?)"后,寄存器并没有直接发生变化,但寄存器可以用于方便地访问和操作数组中的元素。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值